#pragma once
#include<iostream>
#include<ctime>
#include<cstdio>
#include<mysql/mysql.h>
#include<string>
#include<vector>
#include<fstream>
#include<sstream>
#include<memory>
#include<jsoncpp/json/json.h>

#define NORMAL 1
#define WARING 2
#define ERROR 3
#define FATAL 4

#define LOG_NORMAL "log.normal"
#define LOG_ERR "log.error"
#define MESSAGE_BUFF 1024
#define TIME_BUFF 100

FILE *cur = nullptr;
FILE *normal_fd = nullptr;
FILE *error_fd = nullptr;


// void open_log_file()
// {
//     cur = nullptr;
//     normal_fd = fopen(LOG_NORMAL, "a");
//     error_fd = fopen(LOG_ERR, "a");

//     if (normal_fd != nullptr && error_fd != nullptr)
//     {
//         if (degree == NORMAL || degree == WARING)
//             cur = normal_fd;
//         else if (degree == ERROR || degree == FATAL)
//             cur = error_fd;

//         fprintf(cur, "%s %s\n", buff, error_message.c_str());
//         fclose(normal_fd);
//         fclose(error_fd);
//     }
// }


#define log_message(degree, format, ...) do {\
    time_t now_time = time(NULL);\
    struct tm* cur_time = localtime(&now_time);\
    char display_time[64] = {0};\
    strftime(display_time, 63, "%Y:%m:%d %H:%M:%S", cur_time);\
    cur = nullptr; normal_fd = fopen(LOG_NORMAL, "a"); error_fd = fopen(LOG_ERR, "a");\
    if (normal_fd != nullptr && error_fd != nullptr){if (degree == NORMAL || degree == WARING) cur = normal_fd;\
    else if (degree == ERROR || degree == FATAL) cur = error_fd; \
    fprintf(cur,"[TIME: %s  AERA: %s: %d] " format "\n", display_time, __FILE__, __LINE__, ##__VA_ARGS__);\
    fclose(normal_fd);fclose(error_fd);}\
}while(0)





class Mysql_API{
public:
    static MYSQL* mysql_create(const std::string& host, const std::string& user, 
    const std::string& passwd, const std::string& db, const unsigned int port)
    {
        //1.创建并初始化MySQL句柄
        MYSQL* mysql = new MYSQL;
        mysql_init(mysql);

        //2.连接MySQL服务器
        if (mysql_real_connect(mysql, host.c_str(), user.c_str(), passwd.c_str(),
        db.c_str(), port, NULL, 0) == nullptr)
        {
            log_message(ERROR, "数据库连接失败");
            mysql_destory(mysql);
        }

        //3.设置字符集为utf8
        if (mysql_set_character_set(mysql, "utf8") != 0)
        {
            log_message(ERROR, "数据库字符集设置失败");
            mysql_destory(mysql);
        }

        return mysql;
    }

    static bool mysql_exec(MYSQL* mysql, const std::string& sql_commend)
    {
        int query_result = mysql_query(mysql, sql_commend.c_str());
        if (query_result != 0)
        {
            log_message(ERROR, "sql执行出错原因：%s", mysql_error(mysql));
            std::string error_message = "执行失败->";
            error_message += sql_commend;
            log_message(ERROR, "%s", error_message.c_str());
            mysql_destory(mysql);
            return false;
        }
        return true;
    }

    static void mysql_destory(MYSQL* mysql)
    {
        if (mysql != nullptr)
        {
            mysql_close(mysql);
            log_message(WARING, "数据库已关闭");
        }
    }
};



class String_API
{
public:
    static int string_split(const std::string &src, const std::string &sep, std::vector<std::string> &ret)
    {
        int pos = 0, index = 0;
        while (index < src.size())
        {
            pos = src.find(sep, index);
            if (pos == std::string::npos)
            {
                ret.push_back(src.substr(index));
                break;
            }

            if (pos == index)
            {
                index += sep.size();
                continue;
            }
            ret.push_back(src.substr(index, pos - index));
            index = pos + sep.size();
        }

        return ret.size();
    }
};




class Json_API{
public:
    static bool serialize(const Json::Value& root, std::string& str)
    {
        Json::StreamWriterBuilder swb;
        std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
        std::stringstream out_msg;
        int check = sw->write(root, &out_msg);
        if (check != 0){ log_message(ERROR, "消息序列化失败"); return false;}
        str = out_msg.str();
        return true;
    }

    static bool deserialize(const std::string& str, Json::Value& root)
    {
        Json::CharReaderBuilder crb;
        std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
        std::string error_msg;
        if (cr->parse(str.c_str(), str.c_str()+str.size(), &root, &error_msg) == false)
        {
            log_message(ERROR, "消息反序列化失败 %s", error_msg.c_str()); 
            return false;
        }
        return true;
    }

};


class File_API{
public:
    static bool read_file(const std::string& file_name, std::string& file_content)
    {
        //打开文件
        std::ifstream ifs(file_name, std::ios::binary);
        if (ifs.is_open() == false)
        {
            log_message(ERROR, "文件 %s 打开失败", file_name.c_str());
            return false;
        }

        //获取文件大小
        size_t fsize = 0;
        ifs.seekg(0, std::ios::end);
        fsize = ifs.tellg();
        ifs.seekg(0, std::ios::beg);

        //std::cout<< fsize << std::endl;
        file_content.resize(fsize);

        //将所有数据读出来
        ifs.read(&file_content[0], fsize);
        if (ifs.good() == false)
        {
            log_message(ERROR, "文件 %s 读取失败", file_name.c_str());
            return false;
        }

        ifs.close();
        return true;
    }
};


